home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2002 #3 / Amiga Plus CD - 2002 - No. 03.iso / AmigaPlus / Tools / Development / stunnel-4.04 / _src / src / protocol.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-01  |  7.9 KB  |  266 lines

  1. /*
  2.  *   stunnel       Universal SSL tunnel
  3.  *   Copyright (c) 1998-2003 Michal Trojnara <Michal.Trojnara@mirt.net>
  4.  *                 All Rights Reserved
  5.  *
  6.  *   This program is free software; you can redistribute it and/or modify
  7.  *   it under the terms of the GNU General Public License as published by
  8.  *   the Free Software Foundation; either version 2 of the License, or
  9.  *   (at your option) any later version.
  10.  *
  11.  *   This program is distributed in the hope that it will be useful,
  12.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *   GNU General Public License for more details.
  15.  *
  16.  *   You should have received a copy of the GNU General Public License
  17.  *   along with this program; if not, write to the Free Software
  18.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  *
  20.  *   In addition, as a special exception, Michal Trojnara gives
  21.  *   permission to link the code of this program with the OpenSSL
  22.  *   library (or with modified versions of OpenSSL that use the same
  23.  *   license as OpenSSL), and distribute linked combinations including
  24.  *   the two.  You must obey the GNU General Public License in all
  25.  *   respects for all of the code used other than OpenSSL.  If you modify
  26.  *   this file, you may extend this exception to your version of the
  27.  *   file, but you are not obligated to do so.  If you do not wish to
  28.  *   do so, delete this exception statement from your version.
  29.  */
  30.  
  31. #include "common.h"
  32. #include "prototypes.h"
  33.  
  34. /* protocol-specific function prototypes */
  35. static int smb_client(CLI *);
  36. static int smb_server(CLI *);
  37. static int smtp_client(CLI *);
  38. static int smtp_server(CLI *);
  39. static int pop3_client(CLI *);
  40. static int pop3_server(CLI *);
  41. static int nntp_client(CLI *);
  42. static int nntp_server(CLI *);
  43. static int telnet_client(CLI *);
  44. static int telnet_server(CLI *);
  45. static int RFC2487(int);
  46.  
  47. int negotiate(CLI *c) {
  48.     if(!c->opt->protocol)
  49.         return 0; /* No protocol negotiations */
  50.     log(LOG_DEBUG, "Negotiations for %s(%s side) started", c->opt->protocol,
  51.         options.option.client ? "client" : "server");
  52.     if(!strcmp(c->opt->protocol, "smb")) {
  53.         if(options.option.client)
  54.             return smb_client(c);
  55.         else
  56.             return smb_server(c);
  57.     }
  58.     if(!strcmp(c->opt->protocol, "smtp")) {
  59.         if(options.option.client)
  60.             return smtp_client(c);
  61.         else
  62.             return smtp_server(c);
  63.     }
  64.     if(!strcmp(c->opt->protocol, "pop3")) {
  65.         if(options.option.client)
  66.             return pop3_client(c);
  67.         else
  68.             return pop3_server(c);
  69.     }
  70.     if(!strcmp(c->opt->protocol, "nntp")) {
  71.         if(options.option.client)
  72.             return nntp_client(c);
  73.         else
  74.             return nntp_server(c);
  75.     }
  76.     if(!strcmp(c->opt->protocol, "telnet")) {
  77.         if(options.option.client)
  78.             return telnet_client(c);
  79.         else
  80.             return telnet_server(c);
  81.     }
  82.     log(LOG_ERR, "Protocol %s not supported in %s mode",
  83.         c->opt->protocol, options.option.client ? "client" : "server");
  84.     return -1;
  85. }
  86.  
  87. static int smb_client(CLI *c) {
  88.     log(LOG_ERR, "Protocol not supported");
  89.     return -1;
  90. }
  91.  
  92. static int smb_server(CLI *c) {
  93.     log(LOG_ERR, "Protocol not supported");
  94.     return -1;
  95. }
  96.  
  97. static int smtp_client(CLI *c) {
  98.     char line[STRLEN];
  99.     
  100.     do { /* Copy multiline greeting */
  101.         if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  102.             return -1;
  103.         if(fdprintf(c, c->local_wfd.fd, "%s", line)<0)
  104.             return -1;
  105.     } while(strncmp(line,"220-",4)==0);
  106.  
  107.     if(fdprintf(c, c->remote_fd.fd, "EHLO localhost")<0) /* Send an EHLO command */
  108.         return -1;
  109.     do { /* Skip multiline reply */
  110.         if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  111.             return -1;
  112.     } while(strncmp(line,"250-",4)==0);
  113.     if(strncmp(line,"250 ",4)!=0) { /* Error */
  114.         log(LOG_ERR, "Remote server is not RFC 1425 compliant");
  115.         return -1;
  116.     }
  117.  
  118.     if(fdprintf(c, c->remote_fd.fd, "STARTTLS")<0) /* Send STARTTLS command */
  119.         return -1;
  120.     do { /* Skip multiline reply */
  121.         if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  122.             return -1;
  123.     } while(strncmp(line,"220-",4)==0);
  124.     if(strncmp(line,"220 ",4)!=0) { /* Error */
  125.         log(LOG_ERR, "Remote server is not RFC 2487 compliant");
  126.         return -1;
  127.     }
  128.     return 0;
  129. }
  130.  
  131. static int smtp_server(CLI *c) {
  132.     char line[STRLEN];
  133.  
  134.     if(RFC2487(c->local_rfd.fd)==0)
  135.         return 0; /* Return if RFC 2487 is not used */
  136.  
  137.     if(fdscanf(c, c->remote_fd.fd, "220%[^\n]", line)!=1) {
  138.         log(LOG_ERR, "Unknown server welcome");
  139.         return -1;
  140.     }
  141.     if(fdprintf(c, c->local_wfd.fd, "220%s + stunnel", line)<0)
  142.         return -1;
  143.     if(fdscanf(c, c->local_rfd.fd, "EHLO %[^\n]", line)!=1) {
  144.         log(LOG_ERR, "Unknown client EHLO");
  145.         return -1;
  146.     }
  147.     if(fdprintf(c, c->local_wfd.fd, "250-%s Welcome", line)<0)
  148.         return -1;
  149.     if(fdprintf(c, c->local_wfd.fd, "250 STARTTLS")<0)
  150.         return -1;
  151.     if(fdscanf(c, c->local_rfd.fd, "STARTTLS", line)<0) {
  152.         log(LOG_ERR, "STARTTLS expected");
  153.         return -1;
  154.     }
  155.     if(fdprintf(c, c->local_wfd.fd, "220 Go ahead")<0)
  156.         return -1;
  157.     return 0;
  158. }
  159.  
  160. static int pop3_client(CLI *c) {
  161.     char line[STRLEN];
  162.  
  163.     if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  164.         return -1;
  165.     if(strncmp(line,"+OK ",4)) {
  166.         log(LOG_ERR, "Unknown server welcome");
  167.         return -1;
  168.     }
  169.     if(fdprintf(c, c->local_wfd.fd, "%s", line)<0)
  170.         return -1;
  171.     if(fdprintf(c, c->remote_fd.fd, "STLS")<0)
  172.         return -1;
  173.     if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  174.         return -1;
  175.     if(strncmp(line,"+OK ",4)) {
  176.         log(LOG_ERR, "Server does not support TLS");
  177.         return -1;
  178.     }
  179.     return 0;
  180. }
  181.  
  182. static int pop3_server(CLI *c) {
  183.     char line[STRLEN];
  184.  
  185.     if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  186.         return -1;
  187.     if(fdprintf(c, c->local_wfd.fd, "%s + stunnel", line)<0)
  188.         return -1;
  189.     if(fdscanf(c, c->local_rfd.fd, "%[^\n]", line)<0)
  190.         return -1;
  191.     if(!strncmp(line, "CAPA", 4)) { /* Client wants RFC 2449 extensions */
  192.         if(fdprintf(c, c->local_wfd.fd, "-ERR Stunnel does not support capabilities")<0)
  193.             return -1;
  194.         if(fdscanf(c, c->local_rfd.fd, "%[^\n]", line)<0)
  195.             return -1;
  196.     }
  197.     if(strncmp(line, "STLS", 4)) {
  198.         log(LOG_ERR, "Client does not want TLS");
  199.         return -1;
  200.     }
  201.     if(fdprintf(c, c->local_wfd.fd, "+OK Stunnel starts TLS negotiation")<0)
  202.         return -1;
  203.  
  204.     return 0;
  205. }
  206.  
  207. static int nntp_client(CLI *c) {
  208.     char line[STRLEN];
  209.  
  210.     if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  211.         return -1;
  212.     if(strncmp(line,"200 ",4) && strncmp(line,"201 ",4)) {
  213.         log(LOG_ERR, "Unknown server welcome");
  214.         return -1;
  215.     }
  216.     if(fdprintf(c, c->local_wfd.fd, "%s", line)<0)
  217.         return -1;
  218.     if(fdprintf(c, c->remote_fd.fd, "STARTTLS")<0)
  219.         return -1;
  220.     if(fdscanf(c, c->remote_fd.fd, "%[^\n]", line)<0)
  221.         return -1;
  222.     if(strncmp(line,"382 ",4)) {
  223.         log(LOG_ERR, "Server does not support TLS");
  224.         return -1;
  225.     }
  226.     return 0;
  227. }
  228.  
  229. static int nntp_server(CLI *c) {
  230.     log(LOG_ERR, "Protocol not supported in server mode");
  231.     return -1;
  232. }
  233.  
  234. static int telnet_client(CLI *c) {
  235.     log(LOG_ERR, "Protocol not supported");
  236.     return -1;
  237. }
  238.  
  239. static int telnet_server(CLI *c) {
  240.     log(LOG_ERR, "Protocol not supported");
  241.     return -1;
  242. }
  243.  
  244. static int RFC2487(int fd) {
  245.     fd_set         fdsRead;
  246.     struct timeval timeout;
  247.  
  248.     FD_ZERO(&fdsRead);
  249.     FD_SET(fd, &fdsRead);
  250.     timeout.tv_sec=timeout.tv_usec=0; /* don't wait */
  251.  
  252.     switch(sselect(fd+1, &fdsRead, NULL, NULL, &timeout)) {
  253.     case 0: /* fd not ready to read */
  254.         log(LOG_DEBUG, "RFC 2487 detected");
  255.         return 1;
  256.     case 1: /* fd ready to read */
  257.         log(LOG_DEBUG, "RFC 2487 not detected");
  258.         return 0;
  259.     default: /* -1 */
  260.         sockerror("RFC2487 (select)");
  261.         return -1;
  262.     }
  263. }
  264.  
  265. /* End of protocol.c */
  266.